import {
  BadRequestException,
  Injectable,
  InternalServerErrorException,
  Logger,
  Req,
} from '@nestjs/common';
import { CreateArticleDto } from './dto/create-article.dto';
import { UpdateArticleDto } from './dto/update-article.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Like, Repository } from 'typeorm';
import { Article } from './entities/article.entity';
import { ArticleColumnRelated } from './entities/article-column-related.entity';
import { SpecialColumn } from 'src/special-column/entities/special-column.entity';
import {
  removeUserData,
  setCreatedUser,
  removeUnnecessaryData,
  setUpdatedUser,
  setDeletedUser,
} from 'src/utils';
import { ListArticleDto } from './dto/list-article.dto';

@Injectable()
export class ArticleService {
  private logger = new Logger('ArticleService');

  constructor(
    @InjectRepository(Article)
    private readonly articleRepository: Repository<Article>,
    @InjectRepository(ArticleColumnRelated)
    private readonly articleColumnRelatedRepository: Repository<ArticleColumnRelated>,
    @InjectRepository(SpecialColumn)
    private readonly specialColumnRepository: Repository<SpecialColumn>,
  ) {}

  // 异步获取文章专栏关联数据
  async getArticleColumnData(columnIds, savedArticle) {
    return await Promise.all(
      columnIds.map(async (columnId) => {
        const articleColumn = new ArticleColumnRelated();
        // 文章信息
        articleColumn.articleId = savedArticle.id;
        articleColumn.articleTitle = savedArticle.title;
        // 专栏信息
        const column = await this.specialColumnRepository.findOne({
          where: { id: columnId, isDeleted: 0 },
        });
        articleColumn.columnId = columnId;
        articleColumn.columnTitle = column?.title;

        return articleColumn;
      }),
    );
  }

  async createArticleWithColumns(
    createArticleDto: CreateArticleDto,
    req,
  ): Promise<any> {
    return await this.articleRepository.manager.transaction(async (manager) => {
      // 创建文章
      const article = new Article();
      article.title = createArticleDto.title;
      article.description = createArticleDto.description;
      article.content = createArticleDto.content;

      // 设置创建用户信息
      const createdArticle = setCreatedUser(req, article);

      const savedArticle = await manager.save(createdArticle);

      // 创建文章专栏关联记录
      if (createArticleDto?.columnIds?.length) {
        const articleColumns = await this.getArticleColumnData(
          createArticleDto?.columnIds,
          savedArticle,
        );

        await manager.save(articleColumns);
      }

      return savedArticle;
    });
  }

  async validateHasColumnIds(createArticleDto) {
    if (createArticleDto?.columnIds?.length) {
      const columnIds = await this.specialColumnRepository.find({
        select: ['id'],
        where: {
          id: In(createArticleDto?.columnIds),
          isDeleted: 0,
        },
      });

      const columnIdArr = columnIds.map((item) => item.id);

      for (const id of createArticleDto?.columnIds) {
        if (!columnIdArr.includes(id)) {
          throw new BadRequestException(`专栏ID ${id} 不存在`);
        }
      }
    }
  }

  // 新建文章
  async create(createArticleDto: CreateArticleDto, @Req() req) {
    // 先查询文章的专栏id是否存在
    if (createArticleDto?.columnIds?.length) {
      await this.validateHasColumnIds(createArticleDto);
    }

    // 新建文章
    try {
      const article = await this.createArticleWithColumns(
        createArticleDto,
        req,
      );

      return {
        id: article.id,
        title: article.title,
        description: article.description,
      };
    } catch (error) {
      this.logger.error('文章新建失败：', error);
      throw new InternalServerErrorException('文章新建失败');
    }
  }

  // 分页查询文章
  async findAllByPage(query: ListArticleDto) {
    try {
      // 分页查询
      const [data, total] = await this.articleRepository.findAndCount({
        where: {
          id: query.id,
          title: query.title ? Like(`%${query.title}%`) : null,
          isDeleted: 0,
        },
        order: {
          id: 'DESC',
        },
        skip: (query.pageNum - 1) * query.pageSize,
        take: query.pageSize,
      });

      this.logger.log('@@@ 分页查询文章:', data);

      return {
        list: removeUnnecessaryData(data),
        pageNum: Number(query.pageNum),
        pageSize: Number(query.pageSize),
        total,
      };
    } catch (error) {
      this.logger.error('@@@@ 账号列表查询失败:', error);
      throw new InternalServerErrorException('账号列表查询失败');
    }
  }

  async queryColumnIdsByArticleId(articleId) {
    const columns = await this.articleColumnRelatedRepository.find({
      select: ['columnId'],
      where: { articleId },
    });

    return columns.map((item) => item.columnId);
  }

  // 查询文章详情
  async findOne(id: number) {
    if (!id) {
      throw new BadRequestException('id必填');
    }
    try {
      const data = await this.articleRepository.findOne({
        where: { id, isDeleted: 0 },
      });
      const filterData = removeUserData(data);

      this.logger.log('@@@ 查询文章详情', filterData);

      // 关联查询返回专栏id
      const columnIds = await this.queryColumnIdsByArticleId(id);

      return {
        ...filterData,
        columnIds,
      };
    } catch (error) {
      this.logger.error('@@@@ 查询文章详情失败:', error);
      throw new InternalServerErrorException('查询文章详情失败');
    }
  }

  async updateArticleWithColumns(
    id,
    updateArticleDto: UpdateArticleDto,
    req,
  ): Promise<any> {
    return await this.articleRepository.manager.transaction(async (manager) => {
      // 获取原始文章
      const article = await manager.findOne(Article, {
        where: { id, isDeleted: 0 },
      });

      if (!article) {
        throw new BadRequestException(`文章ID ${id} 没有找到`);
      }

      // 更新文章基本信息
      article.title = updateArticleDto.title;
      article.description = updateArticleDto.description;
      article.content = updateArticleDto.content;

      // 设置更新用户信息
      const updatedArticle = setUpdatedUser(req, article);

      const savedArticle = await manager.save(updatedArticle);

      // 处理文章专栏关联记录
      const existingRelations = await manager.find(ArticleColumnRelated, {
        where: { articleId: id },
      });

      this.logger.log('@@@@ existingRelations', existingRelations);

      // 需要添加的新关联
      const newRelationsToAdd = updateArticleDto.columnIds.filter(
        (columnId) =>
          !existingRelations.some((item) => item.columnId === columnId),
      );

      this.logger.log('@@@@ newRelationsToAdd', newRelationsToAdd);

      // 需要标记为已删除的旧关联
      const oldRelationsToMarkDeleted = existingRelations.filter(
        (rel) => !updateArticleDto.columnIds.includes(rel.columnId),
      );

      this.logger.log(
        '@@@@ oldRelationsToMarkDeleted',
        oldRelationsToMarkDeleted,
      );

      // 添加新的关联记录
      for (const columnId of newRelationsToAdd) {
        const column = await this.specialColumnRepository.findOneBy({
          id: columnId,
          isDeleted: 0,
        });
        const newRelation = new ArticleColumnRelated();
        newRelation.articleId = id;
        newRelation.articleTitle = savedArticle.title;
        newRelation.columnId = column.id;
        newRelation.columnTitle = column.title;
        await manager.save(newRelation);
      }

      // 标记旧的关联记录为已删除
      for (const relation of oldRelationsToMarkDeleted) {
        relation.isDeleted = 1; // 标记为已删除
        await manager.save(relation);
      }

      // 给所有记录修改标题
      for (const relation of existingRelations) {
        relation.articleTitle = savedArticle.title; // 文章标题修改
        await manager.save(relation);
      }

      return savedArticle;
    });
  }

  // 修改文章
  async update(id: number, updateArticleDto: UpdateArticleDto, @Req() req) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    this.logger.log('@@@@ 修改文章 updateArticleDto', updateArticleDto);

    // 先查询文章的专栏id是否存在
    if (updateArticleDto?.columnIds?.length) {
      await this.validateHasColumnIds(updateArticleDto);
    }

    // 更新文章
    try {
      const article = await this.updateArticleWithColumns(
        id,
        updateArticleDto,
        req,
      );

      return {
        id: article.id,
        title: article.title,
        description: article.description,
      };
    } catch (error) {
      this.logger.error('文章更新失败：', error);
      throw new InternalServerErrorException('文章更新失败');
    }
  }

  // 软删除文章专栏关联表
  async softDeleteArticleColumnRelations(articleId: number) {
    const relations = await this.articleColumnRelatedRepository.find({
      where: { articleId, isDeleted: 0 },
    });

    for (const relation of relations) {
      relation.isDeleted = 1; // 标记为已删除
      await this.articleColumnRelatedRepository.save(relation);
    }
  }

  // 软删除单个文章
  async softDeleteArticle(id: number, @Req() req) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    try {
      const article = new Article();
      const removedArticle = setDeletedUser(req, article);

      this.logger.log('@@@ 软删除单个文章 removedArticle', removedArticle);

      await this.articleRepository.update(id, removedArticle);

      // 软删除文章专栏关联表
      await this.softDeleteArticleColumnRelations(id);

      return { message: '删除成功' };
    } catch (error) {
      this.logger.error('@@@@ 删除文章失败:', error);
      throw new InternalServerErrorException('删除文章失败');
    }
  }
}
